/*
 * Copyright (c) 2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/* Standard includes                                                          */
#include <mqueue.h>

/* POSIX Header files */
#include <semaphore.h>

/* TI-DRIVERS Header files */
#include <ti/drivers/net/wifi/simplelink.h>
#include <ti/net/mqtt/mqttserver.h>
#include <ti/net/mqtt/mqttclient.h>

/* Application Name and Version*/
#define APPLICATION_NAME        "Wi-Fi E-Lock Demo"
#define APPLICATION_VERSION     "1.0.0"

/* Defines used to exclude various functionality from build
 * Note: Control and network interface are essential to the
 * project and should not be disabled
 *
 */
#define CONTROL             (1) // Enables control task
#define NETWORK_IF          (1) // Enables network interface task
#define APSC_PROVISIONING   (0) // Enables AP Provisioning and TI SmartConfig
#define BLE_PROVISIONING    (0) // Enables BLE Provisioning if using CC2640R2F as SNP
#define OTA                 (1) // Enables OTA software update state machine
#define MQTT                (1) // Enables MQTT client for receiving messages from the cloud
#define MOTOR               (0) // Enables the PWM/GPIO interface for controlling DRV8837EVM
#define SENSORS             (0) // Enables reading sensors when using BOOSTXL-SENSORS

#define NUM_TASKS_ENABLED   (CONTROL + MOTOR + MQTT + NETWORK_IF + APSC_PROVISIONING + BLE_PROVISIONING + OTA + SENSORS)

#define HTTPS_ENABLE        (1)
#define SECURED_AP_ENABLE   (1)
#define PUSH_BUTTONS        (1)

/* Priority of Wi-Fi interface in SimpleLink NetSock Driver */
#define SLNET_IF_WIFI_PRIO       (5)

#define SPAWN_TASK_PRIORITY     (9)

#define TASK_STACK_SIZE                 (1024)
#define LOCAL_NETWORK_TASK_STACK_SIZE   (1366)
#define PROVISIONING_TASK_SIZE          (1366)
#define MQTT_TASK_SIZE                  (1878)
#define MQTT_CLIENT_RX_TASK_SIZE        (1536)
#define MOTOR_TASK_SIZE                 (512)
#define CONTROL_TASK_SIZE               (512)
#define OTA_TASK_SIZE                   (5000)//(2902)
#define BLE_TASK_SIZE                   (1878)
#define BMI_TASK_STACK_SIZE             (854)

/* CC3220 Specific */
#define OCP_REGISTER_INDEX      (0)
#define OCP_REGISTER_OFFSET     (10)

#define SSID_LEN_MAX            (32)
#define BSSID_LEN_MAX           (6)

/* Values for below macros shall be modified as per access-point(AP)          */
/* properties SimpleLink device will connect to following AP when application */
/* is executed.                                                               */

/* AP SSID                                                                    */
#define SSID_NAME               "AP SSID "
/* Security type (OPEN or WEP or WPA)                                         */
#define SECURITY_TYPE           SL_WLAN_SEC_TYPE_WPA_WPA2
/* Password of the secured AP                                                 */
#define SECURITY_KEY            "password"



#define SSID_AP_MODE            "mysimplelink-DoorLock"
#define SEC_TYPE_AP_MODE        SL_WLAN_SEC_TYPE_WPA_WPA2
#define PASSWORD_AP_MODE        "1234567890"

#define SL_STOP_TIMEOUT             (200)
#define LSI_DURATION_IN_MSEC        (500)

#define PROFILE_ASYNC_EVT_TIMEOUT   (7)     /*In sec. Used for connecting to stored profile */
#define ASYNC_EVT_TIMEOUT                   (5000)  /* In msecs. Used to detect good/bad sl_start() */

#define PING_PASS_PERCENTAGE        (10)
#define PING_INTERVAL               (1)  /* In secs */
#define PING_TIMEOUT                (3)  /* In secs */
#define PING_PKT_SIZE               (20)    /* In bytes */
#define NO_OF_ATTEMPTS              (3)
#define HOST_NAME                   "www.ti.com"

/* Defining Number of subscription topics                                     */
#define SUBSCRIPTION_TOPIC_COUNT 4

/* Defining Subscription Topic Values                                         */
#define SUBSCRIPTION_TOPIC0      "/Broker/To/cc32xx/doorLock"
#define SUBSCRIPTION_TOPIC1      "/cc3220/doorLock/%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x/LockControl"
#define SUBSCRIPTION_TOPIC2      "/cc3220/doorLock/%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x/LockStatus"
#define SUBSCRIPTION_TOPIC3      "/cc3220/doorLock/%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x/LockOTA"

/* Defining Publish Topic Values                                              */
#define PUBLISH_TOPIC_COUNT     1
#define PUBLISH_DATA_COUNT      2

#define PUBLISH_TOPIC0           "/cc3220/doorLock/%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x/LockState"

/* Define publish data format for PUBLISH_TOPIC0, actual data will fill fields as needed */
#define PUBLISH_TOPIC0_LOCKED   "{ \"state\" : \"locked\"}"
#define PUBLISH_TOPIC0_UNLOCKED   "{ \"state\" : \"unlocked\"}"

#define ERR_PRINT(x) Display_printf(display, 0, 0,"Error [%d] at line [%d] in function [%s]  \n\r",x,__LINE__,__FUNCTION__)

/* Loop forever, user can change it as per application's requirement          */
#define LOOP_FOREVER() \
            {\
                while(1); \
            }
/* check the error code and handle it                                         */
#define ASSERT_ON_ERROR(error_code)\
            {\
                 if(error_code < 0) \
                   {\
                        ERR_PRINT(error_code);\
                        return error_code;\
                 }\
            }

/* Basic Macros for Manipulating Status Variables                            */
#define CLR_STATUS_BIT_ALL(status_variable)  (status_variable = 0)
#define SET_STATUS_BIT(status_variable, bit) (status_variable |= (1<<(bit)))
#define CLR_STATUS_BIT(status_variable, bit) (status_variable &= ~(1<<(bit)))
#define CLR_STATUS_BIT_ALL(status_variable)  (status_variable = 0)
#define GET_STATUS_BIT(status_variable, bit) (0 != (status_variable & (1<<(bit))))

/* Network Specific Status Bit Macros                                        */
#define IS_NW_PROCSR_ON(status_variable)    \
                GET_STATUS_BIT(status_variable, AppStatusBits_NwpInit)

#define IS_CONNECTED(status_variable)       \
                GET_STATUS_BIT(status_variable, AppStatusBits_Connection)

#define IS_IP_LEASED(status_variable)       \
                GET_STATUS_BIT(status_variable, AppStatusBits_IpLeased)

#define IS_IP_ACQUIRED(status_variable)     \
                GET_STATUS_BIT(status_variable, AppStatusBits_IpAcquired)

#define IS_IPV6L_ACQUIRED(status_variable)  \
                GET_STATUS_BIT(status_variable, AppStatusBits_Ipv6lAcquired)

#define IS_IPV6G_ACQUIRED(status_variable)  \
                GET_STATUS_BIT(status_variable, AppStatusBits_Ipv6gAcquired)

#define IS_SMART_CFG_START(status_variable) \
                GET_STATUS_BIT(status_variable, AppStatusBits_SmartconfigStart)

#define IS_CONNECT_FAILED(status_variable)  \
                GET_STATUS_BIT(status_variable, AppStatusBits_Connection)

#define IS_PING_DONE(status_variable)       \
                GET_STATUS_BIT(status_variable, AppStatusBits_PingDone)

#define IS_AUTHENTICATION_FAILED(status_variable)   \
            GET_STATUS_BIT(status_variable, AppStatusBits_AuthenticationFailed)

/*!
 *  \brief  Function pointer to the event handler
 */
typedef int32_t (*fptr_EventHandler)();

/* Application specific status/error codes */
typedef enum
{
    /* Choosing -0x7D0 to avoid overlap w/ host-driver's error codes */
    AppStatusCodes_LanConnectionFailed = -0x7D0,
    AppStatusCodes_InternetConnectionFailed = AppStatusCodes_LanConnectionFailed - 1,
    AppStatusCodes_DeviceNotInStationMode = AppStatusCodes_InternetConnectionFailed - 1,
    AppStatusCodes_StatusCodeMax = -0xBB8
}AppStatusCodes;

typedef enum
{
    AppStatusBits_NwpInit = 0,                  /* If this bit is set: Network Processor is powered up */
    AppStatusBits_Connection = 1,               /* If this bit is set: the device is connected to the AP or client is connected to device (AP) */
    AppStatusBits_IpLeased = 2,                 /* If this bit is set: the device has leased IP to any connected client */
    AppStatusBits_IpAcquired = 3,               /* If this bit is set: the device has acquired an IP */
    AppStatusBits_SmartconfigStart = 4,         /* If this bit is set: the SmartConfiguration process is started from SmartConfig app */
    AppStatusBits_ConnectionFailed = 5,         /* If this bit is set: the device(P2P mode) connection to client(or reverse way) is failed */
    AppStatusBits_PingDone = 6,                 /* If this bit is set: the device has completed the ping operation */
    AppStatusBits_Ipv6lAcquired = 7,            /* If this bit is set: the device has acquired an IPv6 address */
    AppStatusBits_Ipv6gAcquired = 8,           /* If this bit is set: the device has acquired an IPv6 address */
    AppStatusBits_AuthenticationFailed = 9,
    AppStatusBits_ResetRequired = 10,
    AppStatusBits_ResetOccurred = 11,
    AppStatusBits_RTCRefreshRequired = 12,
    AppStatusBits_APProvInProgress = 13,
    AppStatusBits_BLEProvInProgress = 14,
    AppStatusBits_OtaInProgress = 15,
    AppStatusBits_MqttInitialized = 16,
    AppStatusBits_MqttConnected = 17,
    AppStatusBits_MqttStopInProgress = 18,
}AppStatusBits;

typedef enum
{
    CONTROL_MSG_OTA_START,
    CONTROL_MSG_GENERAL_RESET,
    CONTROL_MSG_OTA_IMAGE_TEST,
    CONTROL_MSG_RETURN_TO_FACTORY_DEFAULT,
    CONTROL_MSG_MAX
}controlQueueMsg;

struct controlMsg
{
    uint32_t            threadID;
    controlQueueMsg          msg;
};

typedef enum
{
    NETWORK_MSG_RECONNECT,
    NETWORK_MSG_PROVISION_START_STOP,
    NETWORK_MSG_SWITCH_PROVISIONING_MODE,
    NETWORK_MSG_APSC_PROV_DONE,
    NETWORK_MSG_BLE_READY,
    NETWORK_MSG_TEST_CREDENTIALS,
    NETWORK_MSG_BLE_PROV_DONE,
    NETWORK_MSG_MAX
}networkIfQueueMsg;

struct networkIfMsg
{
    networkIfQueueMsg msg;
};

/* Control block definition */
typedef struct Application_ControlBlock_t
{
    /* Network IF vars */
    uint8_t                 macAddress[SL_MAC_ADDR_LEN];
    uint32_t                status;                                   /* SimpleLink Status */
    uint32_t                gatewayIP;                                /* Network Gateway IP address */
    uint32_t                staIP;                                    /* Device station IP address */
    uint8_t                 connectionSSID[SSID_LEN_MAX+1];           /* Connection SSID */
    uint8_t                 ssidLen;                                  /* Connection SSID */
    uint8_t                 connectionBSSID[BSSID_LEN_MAX];           /* Connection BSSID */
    uint8_t                 numConnAttempts;                          /* Number of times device attempted to connect to AP */
    SlNetAppPingReport_t    pingReport;
    mqd_t                   networkIfQueue;
    sem_t                   connectionDoneSignal;

    /* Thread monitoring */
    sem_t                   localNetworkReady;
    sem_t                   provReady;
    sem_t                   mqttReady;
    sem_t                   motorReady;
    sem_t                   sensorReady;
    sem_t                   otaReady;
    sem_t                   controlReady;
    sem_t                   bleReady;
    sem_t                   startBarrier;
    mqd_t                   controlQueue;

    /* Provisioning vars */
    mqd_t                   provSignalQueue;
    sem_t                   connectionAsyncEvent;
    sem_t                   provisioningDoneSignal;

    /* MQTT Application vars */
    mqd_t                   mqttQueue;                          /* Queue used to send events to the main client loop */
    MQTTClient_Handle       mqttClientHandle;                    /* Handle for the MQTT interface */

    /* PWM Var */
    bool                    locked;
    mqd_t                   motorQueue;
    uint8_t                 runPWM;                                   /* Indicates if PWM interface to motor driver is enabled */

    /* Sensor Var */
    sem_t                   bmi160Sem;
    mqd_t                   bmi160Queue;
    sem_t                   sensorDisplaySem;

    /* General */
    uint8_t                 role; /* SimpleLink's role - STATION/AP/P2P */
    uint32_t                asyncEvtTimeout; /* Timeout value*/
    uint16_t                timerInts;
    timer_t                 timer;

    /* Identity */
    uint8_t                 lockUDID[16];
}Application_CB;
